package org.pearl.boot.redis.controller;

import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created by TD on 2021/5/14
 */
@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    /**
     * 模拟缓存穿透=》查询某个商品详情
     *
     * @param commodityId 商品ID
     * @return
     */
    @GetMapping("/penetrate")
    public Object penetrate(String commodityId) {
        // ### 方案四：布隆过滤器
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        config.useSingleServer().setPassword("123456");
        // 构造Redisson
        RedissonClient redisson = Redisson.create(config);
        RBloomFilter<String> bloomFilter = redisson.getBloomFilter("commodity");
        // 初始化布隆过滤器：初始化大小、误差率
        bloomFilter.tryInit(100000000L, 0.03);
        // 将商品ID到布隆过滤器中
        bloomFilter.add("a");
        bloomFilter.add("b");
        bloomFilter.add("c");
        bloomFilter.add("d");
        bloomFilter.add("e");
        // 判断商品否存在
        boolean result = bloomFilter.contains(commodityId);
        System.out.println(commodityId + "是否存在：" + result);
        if (result) {
            // 存在查询缓存和数据库
            System.out.println(commodityId + "存在:" + "开始查询数据....");
            // 1. 查询Redis,不存在此商品
            System.out.println("开始查询缓存");
            Object redisResult = redisTemplate.opsForValue().get(commodityId);
            // 2. redis不存在查询数据库
            if (redisResult == null) {
                System.out.println("缓存不存在：开始查询数据库。。。");
                System.out.println("数据库中实际也不存在数据");
                // 方案1：对于数据库为null的值也进行缓存
                //redisTemplate.opsForValue().set(commodityId, "");

            }
        }
        // 不存在直接返回空
        return null;
        // 方案二：接口校验,商品ID长度小于10，直接返回null
/*        if (commodityId.length() <= 10) {
            return null;
        }*/
    }

    private static final Object Lock =new Object();


    @GetMapping("/breakdown")
    @CachePut(value = "",key = "getArgs()")
    @Cacheable(key = "getArgs()")
    @Value("#{systemEnvironment.user.timezone}")
    public Object breakdown(String commodityId) {
        // 1. 查询Redis,此时商品存在，但是已过期
        System.out.println("开始查询缓存");
        // 方案一：预先设置热门数据，设置过期时间为一天
        // redisTemplate.opsForValue().set(commodityId, "信息", 24, TimeUnit.HOURS);
        // 互斥锁
        Object redisResult = redisTemplate.opsForValue().get(commodityId);
        if (redisResult==null){
            synchronized (Lock){
                // 先判断其他线程是否已存入值
                // 2. redis过期，大并发查询数据库
                    System.out.println("缓存过期：开始查询数据库。。。");
                    System.out.println("数据库查询到数据");
            }
        }
        return redisResult;
    }
}
